<?php
/**
 * Context.php	class context
 *
 * @package		
 * @Copyright	(c) All rights reserved
 * @Author		skyCrack <skyCrack@126.com>
 * @Version		$Id$
 */

final class Context
{
	static private $_registry = array();

	static public function loadClass($class, $dirs = null)
	{
		if ( class_exists($class, false) )
		{
			return;
		}

		// autodiscover the path from the class name
		$path = str_replace('_', DIRECTORY_SEPARATOR, $class);

		if ( $dirs === null && $path != $class )
		{
			// use the autodiscovered path
			$dirs = dirname($path);
			$file = basename($path) . '.php';
		}
		else
		{
			$file = $class . '.php';
		}

		self::loadFile($file, $dirs, true);

		if ( !class_exists($class, false) )
		{
			throw new Exception("File \"$file\" was loaded but class \"$class\" was not found within.");
		}
	}

	static public function loadInterface($interface, $dirs = null)
	{
		if ( interface_exists($interface, false) )
		{
			return;
		}

		// autodiscover the path from the interface name
		$path = str_replace('_', DIRECTORY_SEPARATOR, $interface);
		if ( ($dirs === null) && ($path != $interface) )
		{
			// use the autodiscovered path
			$dirs = dirname($path);
			$file = basename($path) . '.php';
		}
		else
		{
			$file = $interface . '.php';
		}

		self::loadFile($file, $dirs, true);

		if ( !interface_exists($interface, false) )
		{
			throw new Exception("File \"$file\" was loaded "
				. "but interface \"$interface\" was not found within.");
		}
	}

	public static function loadFile($filename, $dirs = null, $once = false)
	{
		// security check
		if ( preg_match('/[^a-z0-9\-_.]/i', $filename) )
		{
			throw new Exception('Security check: Illegal character in filename');
		}

		$filespec = $filename;
		if ( $dirs === null )
		{
			$found = self::isReadable($filespec);
		}
		else
		{
			foreach ( (array)$dirs as $dir )
			{
				$filespec = rtrim($dir, "\\/") . DIRECTORY_SEPARATOR . $filename;
				$found = self::isReadable($filespec);
				if ( $found )
				{
					break;
				}
			}
		}

		if ( !$found )
		{
			throw new Exception("File \"$filespec\" was not found.");
		}

		if ( $once )
		{
			include_once($filespec);
		}
		else
		{
			include($filespec);
		}
	}

	static public function isReadable($filename)
	{
		$f = @fopen($filename, 'r', true);
		$readable = is_resource($f);
		if ( $readable )
		{
			fclose($f);
		}
		
		return $readable;
	}

	static public function dump($var, $label = null, $echo = true)
	{
		// format the label
		$label = ($label===null) ? '' : rtrim($label) . ' ';

		// var_dump the variable into a buffer and keep the output
		ob_start();
		var_dump($var);
		$output = ob_get_clean();

		// neaten the newlines and indents
		$output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
		if ( PHP_SAPI == 'cli' )
		{
			$output = PHP_EOL . $label
			. PHP_EOL . $output 
			. PHP_EOL;
		}
		else
		{
			$output = '<pre>'
			. $label
			. htmlentities($output, ENT_QUOTES)
			. '</pre>';
		}

		if ($echo)
		{
			echo($output);
		}

		return $output;
	}

	static public function register($name, $obj)
    {
		if ( !is_string($name) )
		{
			throw new Exception('First argument $name must be a string.');
		}

		// don't register the same name twice
		if ( array_key_exists($name, self::$_registry) )
		{
			throw new Exception("Object named '$name' already registered.  Did you mean to call registry()?");
		}

		// only objects may be stored in the registry
		if ( !is_object($obj) )
		{
			throw new Exception("Only objects may be stored in the registry.");
		}

		$e = '';
		// an object can only be stored in the registry once
		foreach ( self::$_registry as $dup=>$registeredObject )
		{
			if ( $obj === $registeredObject )
			{
				$e = "Duplicate object handle already exists in the registry as \"$dup\".";
				break;
			}
		}

		if ( $e )
		{
			throw new Exception($e);
		}

		self::$_registry[$name] = $obj;
    }

	static public function registry($name = null)
	{
		
		if ( $name === null )
		{
			$registry = array();
			foreach ( self::$_registry as $name=>$obj )
			{
				$registry[$name] = get_class($obj);
			}
			
			return $registry;
		}

		if ( !is_string($name) )
		{
			throw new Exception('First argument $name must be a string, or null to list registry.');
		}

		if ( !array_key_exists($name, self::$_registry) )
		{
			throw new Exception("No object named \"$name\" is registered.");
		}

		return self::$_registry[$name];
	}

	static public function isRegistered($name)
	{
		return isset(self::$_registry[$name]);
	}
}
?>